package ringbuffer

import (
	"errors"
	"fmt"
)

const defaultRingBufferSize = 8

var (
	errNotEnoughSpaceToWrite = errors.New("not enough space to write")
	errIsEmpty               = errors.New("ring-buffer is empty")
)

// RingBuffer 环形缓冲区
type RingBuffer struct {
	buf   []byte
	r     int
	w     int
	cap   int
	empty bool
}

var Get = newRingBuffer(defaultRingBufferSize)

func newRingBuffer(cap int) *RingBuffer {
	return &RingBuffer{
		buf: make([]byte, cap, cap),
		r:   0,
		w:   0,
		cap: cap,
	}
}

func (r *RingBuffer) WriteByte(b byte) error {
	if r.Free() < 1 {
		return errNotEnoughSpaceToWrite
	}
	r.buf[r.w] = b
	r.w++
	if r.w >= r.cap {
		r.w = 0
	}
	r.empty = false
	return nil
}

func (r *RingBuffer) WriteBytes(bs []byte) error {
	if r.Free() < len(bs) {
		return errNotEnoughSpaceToWrite
	}
	l := len(bs)
	copy(r.buf[r.w:r.w+l], bs)
	r.w += l
	return nil
}

func (r *RingBuffer) ReadBytes(n int) ([]byte, error) {
	if r.empty {
		return nil, errIsEmpty
	}

	if r.Used() < n {
		return nil, fmt.Errorf("read too much, only %d left to be read", r.Used())
	}

	b := r.buf[r.r : r.r+n]
	r.r += n
	r.ensureReadIndex()
	return b, nil
}

func (r *RingBuffer) ensureReadIndex() {
	if r.r >= r.cap {
		r.r = 0
	}
	if r.r == r.w {
		r.empty = true
	}
}

func (r *RingBuffer) ReadByte() (byte, error) {
	if r.empty {
		return 0, errIsEmpty
	}
	b := r.buf[r.r]
	r.r++
	r.ensureReadIndex()
	return b, nil
}

func (r *RingBuffer) Full() bool {
	return r.Free() == 0
}

func (r *RingBuffer) Used() int {
	return r.cap - r.Free()
}

func (r *RingBuffer) Free() int {
	if r.r == r.w {
		if r.empty {
			return r.cap
		}
		return 0
	}
	if r.w < r.r {
		return r.r - r.w
	}
	return r.cap - (r.w - r.r)
}

func (r *RingBuffer) Cap() int {
	return r.cap
}

func (r *RingBuffer) Reset() {
	r.w, r.r, r.empty = 0, 0, true
	r.buf = r.buf[:0]
}
